/*
 *  Project:            Gateway_v0.1 -- a RISCV-32I SoC.
 *  Module name:        soc_runtime.
 *  Description:        Top Module of soc_runtime.
 *  Last updated date:  2021.12.03.
 *
 *  Copyright (C) 2021-2023 Junnan Li <lijunnan@nudt.edu.cn>.
 *  Copyright and related rights are licensed under the MIT license.
 *
 *  Noted:
 *    1) rgmii2gmii & gmii_rx2rgmii are processed by language templates;
 *    2) rgmii_rx is constrained by set_input_delay "-2.0 ~ -0.7";
 *    3) 134b pkt data definition: 
 *      [133:132] head tag, 2'b01 is head, 2'b10 is tail;
 *      [131:128] valid tag, 4'b1111 means sixteen 8b data is valid;
 *      [127:0]   pkt data, invalid part is padded with 0;
 *    4) the riscv-32i core is a simplified picoRV32;
 *
 */

`timescale 1ns / 1ps

module soc_runtime(
  //* system input, clk;
   input                clk_125m
  ,input                sys_rst_n

  // //* sgmii port
  // ,input  wire          SFP_REFCLK_P   
  // ,input  wire          SFP_REFCLK_N 
  // ,output wire          FX_RX_P
  // ,output wire          FX_RX_N
  // ,input  wire          FX_TX_P
  // ,input  wire          FX_TX_N

  //* gmii port
  ,input  wire          gmii_rx_clk
  ,input  wire  [7:0]   gmiiRxd
  ,input  wire          gmiiEn
  ,input  wire          gmiiEr
  ,input  wire          gmii_tx_clk
  ,output wire  [7:0]   gmii_txd
  ,output wire          gmii_tx_en
  ,output wire          gmii_tx_er

  //* um
  ,output wire          pktData_valid_gmii
  ,output wire  [133:0] pktData_gmii
  ,output wire  [15:0]  pkt_length_gmii
  ,input  wire          ready_in
  ,input                pktData_valid_um
  ,input        [133:0] pktData_um
);

  //* Connected wire;
  //* Data Flow: gmii_rx - > asfifo_recv -> checkCRC -> gmii2pkt -> UM -> 
  //*   pkt2gmii -> calCRC -> gmii_tx;
  //* Noted: riscv core is initialized in the UM module;
  //* checkCRC & modifyPKT & calCRC;
  wire          gmiiEr_checkCRC, gmiiEr_calCRC, gmiiEr_modifyPKT;
  wire  [7:0]   gmiiTxd_checkCRC, gmiiTxd_calCRC, gmiiTxd_modifyPKT;
  wire          gmiiEn_checkCRC, gmiiEn_calCRC, gmiiEn_modifyPKT;

  // //* sgmii ip core;
  // wire          tx_mac_aclk;
  // wire          rx_mac_aclk;
  // wire          tx_reset;
  // wire          rx_reset;
  // (*mark_debug="true"*)wire       sg_s_axis_tx_tready;
  // (*mark_debug="true"*)wire [7:0] sg_s_axis_tx_tdata;
  // (*mark_debug="true"*)wire       sg_s_axis_tx_tlast;
  // (*mark_debug="true"*)wire       sg_s_axis_tx_tuser;
  // (*mark_debug="true"*)wire       sg_s_axis_tx_tvalid;

  // (*mark_debug="true"*)wire [7:0] sg_m_axis_rx_tdata;
  // (*mark_debug="true"*)wire       sg_m_axis_rx_tlast;
  // (*mark_debug="true"*)wire       sg_m_axis_rx_tuser;
  // (*mark_debug="true"*)wire       sg_m_axis_rx_tvalid;

  
  assign gmii_tx_er = 1'b0;
  
  //* gmii2pkt -> UM -> pkt2gmii -> calCRC;
  wire  [7:0]   gmii_txd_pkt;
  wire          gmii_tx_en_pkt;

  //* asfifo_recv -> checkCRC;
  wire  [7:0]   gmiiRxd_asfifo;
  wire          gmiiEn_asfifo;
  wire          gmiiEr_asfifo;

  //* cnt, haven't been used;
  wire  [31:0]  cntPkt_asynRecvPkt, cntPkt_gmii2pkt, cntPkt_pkt2gmii;
  
  //*************** sub-modules ***************//   
  // SGMII_M_axi_ethernet axi_1g_ethernet (
  //   .gtrefclk_p(gtrefclk_p),                          // input wire gtrefclk_p
  //   .gtrefclk_n(gtrefclk_n),                          // input wire gtrefclk_n
  //   .gtrefclk_out(gtrefclk_out),                      // output wire gtrefclk_out
  //   .gtrefclk_bufg_out(gtrefclk_bufg_out),            // output wire gtrefclk_bufg_out
  //   .txn(txn),                                        // output wire txn
  //   .txp(txp),                                        // output wire txp
  //   .rxn(rxn),                                        // input wire rxn
  //   .rxp(rxp),                                        // input wire rxp
  //   .independent_clock_bufg(independent_clock_bufg),  // input wire independent_clock_bufg
  //   .userclk_out(userclk_out),                        // output wire userclk_out
  //   .userclk2_out(userclk2_out),                      // output wire userclk2_out
  //   .rxuserclk_out(rxuserclk_out),                    // output wire rxuserclk_out
  //   .rxuserclk2_out(rxuserclk2_out),                  // output wire rxuserclk2_out
  //   .resetdone(resetdone),                            // output wire resetdone
  //   .pma_reset_out(pma_reset_out),                    // output wire pma_reset_out
  //   .mmcm_locked_out(mmcm_locked_out),                // output wire mmcm_locked_out
  //   .sgmii_clk_r(sgmii_clk_r),                        // output wire sgmii_clk_r
  //   .sgmii_clk_f(sgmii_clk_f),                        // output wire sgmii_clk_f
  //   .sgmii_clk_en(sgmii_clk_en),                      // output wire sgmii_clk_en
  //   .gmii_txd(gmii_txd),                              // input wire [7 : 0] gmii_txd
  //   .gmii_tx_en(gmii_tx_en),                          // input wire gmii_tx_en
  //   .gmii_tx_er(gmii_tx_er),                          // input wire gmii_tx_er
  //   .gmii_rxd(gmii_rxd),                              // output wire [7 : 0] gmii_rxd
  //   .gmii_rx_dv(gmii_rx_dv),                          // output wire gmii_rx_dv
  //   .gmii_rx_er(gmii_rx_er),                          // output wire gmii_rx_er
  //   .gmii_isolate(gmii_isolate),                      // output wire gmii_isolate
  //   .mdc(mdc),                                        // input wire mdc
  //   .mdio_i(mdio_i),                                  // input wire mdio_i
  //   .mdio_o(mdio_o),                                  // output wire mdio_o
  //   .mdio_t(mdio_t),                                  // output wire mdio_t
  //   .phyaddr(phyaddr),                                // input wire [4 : 0] phyaddr
  //   .configuration_vector(configuration_vector),      // input wire [4 : 0] configuration_vector
  //   .configuration_valid(configuration_valid),        // input wire configuration_valid
  //   .an_interrupt(an_interrupt),                      // output wire an_interrupt
  //   .an_adv_config_vector(an_adv_config_vector),      // input wire [15 : 0] an_adv_config_vector
  //   .an_adv_config_val(an_adv_config_val),            // input wire an_adv_config_val
  //   .an_restart_config(an_restart_config),            // input wire an_restart_config
  //   .speed_is_10_100(speed_is_10_100),                // input wire speed_is_10_100
  //   .speed_is_100(speed_is_100),                      // input wire speed_is_100
  //   .status_vector(status_vector),                    // output wire [15 : 0] status_vector
  //   .reset(reset),                                    // input wire reset
  //   .signal_detect(signal_detect),                    // input wire signal_detect
  //   .gt0_qplloutclk_out(gt0_qplloutclk_out),          // output wire gt0_qplloutclk_out
  //   .gt0_qplloutrefclk_out(gt0_qplloutrefclk_out)    // output wire gt0_qplloutrefclk_out
  // );

  // SGMII_M_axi_ethernet axi_1g_ethernet (
  //   .s_axi_lite_resetn          (sys_rst_n          ),        // input wire tx_axis_aresetn
  //   .s_axi_lite_clk             (clk_125m           ),        // input wire rx_axis_aresetn
  //   .mac_irq                    (                   ),
  //   .tx_mac_aclk                (tx_mac_aclk        ),
  //   .rx_mac_aclk                (rx_mac_aclk        ),
  //   .tx_reset                   (tx_reset           ),
  //   .rx_reset                   (rx_reset           ),
  //   .glbl_rst                   (~sys_rst_n         ),
  //   .tx_ifg_delay               (8'd12              ),        // input wire [7 : 0] tx_ifg_delay
  //   .status_vector              (                   ),
  //   // .rx_axis_filter_tuser       (                   ),
  //   .signal_detect              (1'b1               ),        // input wire signal_detect
  //   .mmcm_locked_out            (                   ),
  //   .rxuserclk_out              (                   ),
  //   .rxuserclk2_out             (                   ),
  //   .userclk_out                (                   ),
  //   .userclk2_out               (                   ),
  //   .pma_reset_out              (                   ),
  //   .gt0_qplloutclk_out         (                   ),
  //   .gt0_qplloutrefclk_out      (                   ),
  //   .ref_clk                    (clk_125m           ),
  //   .gtref_clk_out              (                   ),
  //   .gtref_clk_buf_out          (                   ),
  //   .s_axi_araddr               (11'b0              ),        // input wire [10 : 0] s_axi_araddr
  //   .s_axi_arready              (                   ),        // output wire s_axi_arready
  //   .s_axi_arvalid              (1'b0               ),        // input wire s_axi_arvalid
  //   .s_axi_awaddr               (11'b0              ),        // input wire [10 : 0] s_axi_awaddr
  //   .s_axi_awready              (                   ),        // output wire s_axi_awready
  //   .s_axi_awvalid              (1'b0               ),        // input wire s_axi_awvalid
  //   .s_axi_bready               (1'b0               ),        // input wire s_axi_bready
  //   .s_axi_bresp                (                   ),        // output wire [1 : 0] s_axi_bresp
  //   .s_axi_bvalid               (                   ),        // output wire s_axi_bvalid
  //   .s_axi_rdata                (                   ),        // output wire [31 : 0] s_axi_rdata
  //   .s_axi_rready               (1'b0               ),        // input wire s_axi_rready
  //   .s_axi_rresp                (                   ),        // output wire [1 : 0] s_axi_rresp
  //   .s_axi_rvalid               (                   ),        // output wire s_axi_rvalid
  //   .s_axi_wdata                (32'b0              ),        // input wire [31 : 0] s_axi_wdata
  //   .s_axi_wready               (                   ),        // output wire s_axi_wready
  //   .s_axi_wvalid               (1'b0               ),        // input wire s_axi_wvalid
      
  //   .s_axis_tx_tready           (sg_s_axis_tx_tready),
  //   .s_axis_tx_tdata            (sg_s_axis_tx_tdata ),
  //   .s_axis_tx_tlast            (sg_s_axis_tx_tlast ),
  //   .s_axis_tx_tuser            (sg_s_axis_tx_tuser ),
  //   .s_axis_tx_tvalid           (sg_s_axis_tx_tvalid),

  //   .m_axis_rx_tdata            (sg_m_axis_rx_tdata ),
  //   .m_axis_rx_tlast            (sg_m_axis_rx_tlast ),
  //   .m_axis_rx_tuser            (sg_m_axis_rx_tuser ),
  //   .m_axis_rx_tvalid           (sg_m_axis_rx_tvalid),
  //   .s_axis_pause_tdata         (16'b0              ),        // input wire [15 : 0] s_axis_pause_tdata
  //   .s_axis_pause_tvalid        (1'b0               ),        // input wire s_axis_pause_tvalid     
  //   .rx_statistics_statistics_data    (             ),
  //   .rx_statistics_statistics_valid   (             ),
  //   .tx_statistics_statistics_data    (             ),
  //   .tx_statistics_statistics_valid   (             ),    
  //   .sgmii_rxn                  (FX_TX_N            ),
  //   .sgmii_rxp                  (FX_TX_P            ),
  //   .sgmii_txn                  (FX_RX_N            ),
  //   .sgmii_txp                  (FX_RX_P            ),
  //   .mdio_mdc                   (                   ),
  //   .mdio_mdio_i                (1'b1               ),
  //   .mdio_mdio_o                (                   ),
  //   .mdio_mdio_t                (                   ),
  //   .mgt_clk_clk_n              (SFP_REFCLK_N       ),
  //   .mgt_clk_clk_p              (SFP_REFCLK_P       )
  // );

  //* format transform between gmii with gmii;
  rx_gmii rx_gmii_init(
     .i_clk                     (clk_125m             )
    ,.wrclk                     (gmii_rx_clk          )
    ,.wr_reset                  (sys_rst_n            )

    ,.m_axis_rx_tdata           (gmiiRxd              )
    ,.m_axis_rx_tuser           (1'd0                 )
    ,.m_axis_rx_tvalid          (gmiiEn               )

    ,.o_data_8b                 (gmiiRxd_asfifo       )
    ,.o_data_8b_en              (gmiiEn_asfifo        )
    ,.i_pkt_data_full           (1'b0                 )
  );

  tx_gmii tx_gmii_init(
     .i_clk                     (clk_125m             )
    ,.rdclk                     (gmii_tx_clk          )
    ,.rd_reset                  (sys_rst_n            )
    ,.i_data_8b                 (gmii_txd_pkt         )
    ,.i_data_8b_en              (gmii_tx_en_pkt       )
    ,.s_axis_tx_tready          (1'd1                 )
    ,.s_axis_tx_tdata           (gmii_txd             )
    ,.s_axis_tx_tlast           (                     )
    ,.s_axis_tx_tuser           (                     )
    ,.s_axis_tx_tvalid          (gmii_tx_en           )
  );

  
  //* check CRC of received packets:
  //*   1) discard CRC;
  //*   2) check CRC, TO DO...;
  gmii_crc_check checkCRC(
    .rst_n(sys_rst_n),
    .clk(clk_125m),
    .gmii_dv_i(gmiiEn_asfifo),
    .gmii_er_i(1'b0),
    .gmii_data_i(gmiiRxd_asfifo),
    
    .gmii_en_o(gmiiEn_checkCRC),
    .gmii_er_o(gmiiEr_checkCRC),
    .gmii_data_o(gmiiTxd_checkCRC)
  );
  
  //* gen 134b data;
  //*   1) accumulate sixteen 8b-data to one 128b data;
  //*   2) gen 128b (64b is used) metadata;
  gmii_to_134b_pkt gmii2pkt(
    .rst_n              (sys_rst_n            ),
    .clk                (clk_125m             ),
    // .gmii_data          (gmiiRxd_asfifo       ),
    // .gmii_data_valid    (gmiiEn_asfifo        ),
    .gmii_data          (gmiiTxd_checkCRC     ),
    .gmii_data_valid    (gmiiEn_checkCRC      ),
    .pkt_data           (pktData_gmii         ),
    .pkt_data_valid     (pktData_valid_gmii   ),
    .pkt_length         (pkt_length_gmii      ),
    .ready_in           (ready_in             ),
    .cnt_pkt            (cntPkt_gmii2pkt      )
  );

  //* um;

  //* gen 8b gmii;
  pkt_134b_to_gmii pkt2gmii(
    .rst_n(sys_rst_n),
    .clk(clk_125m),
    .pkt_data_valid(pktData_valid_um),
    .pkt_data(pktData_um),
    // .gmii_data(gmii_txd_pkt),
    // .gmii_data_valid(gmii_tx_en_pkt),
    .gmii_data(gmiiTxd_modifyPKT),
    .gmii_data_valid(gmiiEn_modifyPKT),
    .cnt_pkt(cntPkt_pkt2gmii)
  );
  
  //* add output time for PTP packets;
  // assign gmiiEn_modifyPKT = gmii_tx_en_pkt;
  assign gmiiEr_modifyPKT = 1'b0;
  // assign gmiiTxd_modifyPKT = gmii_txd;
  /* test_modify_packet modifyPkt(
    .rst_n(sys_rst_n),
    .clk(clk_125m),
    .gmii_dv_i(gmiiEn_checkCRC[i_rgmii]),
    .gmii_er_i(gmiiEr_checkCRC[i_rgmii]),
    .gmii_data_i(gmiiTxd_checkCRC[i_rgmii]),
    
    .gmii_en_o(gmiiEn_modifyPKT[i_rgmii]),
    .gmii_er_o(gmiiEr_modifyPKT[i_rgmii]),
    .gmii_data_o(gmiiTxd_modifyPKT[i_rgmii])
  ); */
  
  //* calculate CRC of received packets;
  gmii_crc_calculate calCRC(
    .rst_n(sys_rst_n),
    .clk(clk_125m),
    .gmii_dv_i(gmiiEn_modifyPKT),
    .gmii_er_i(gmiiEr_modifyPKT),
    .gmii_data_i(gmiiTxd_modifyPKT),
    
    .gmii_en_o(gmiiEn_calCRC),
    .gmii_er_o(gmiiEr_calCRC),
    .gmii_data_o(gmiiTxd_calCRC)
  );
  
  assign gmii_tx_en_pkt = gmiiEn_calCRC;
  assign gmii_txd_pkt = gmiiTxd_calCRC;

endmodule
